﻿#region Copyright

// The contents of this file are subject to the Mozilla Public License
//  Version 1.1 (the "License"); you may not use this file except in compliance
//  with the License. You may obtain a copy of the License at
//  
//  http://www.mozilla.org/MPL/
//  
//  Software distributed under the License is distributed on an "AS IS"
//  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//  License for the specific language governing rights and limitations under 
//  the License.
//  
//  The Initial Developer of the Original Code is Robert Smyth.
//  Portions created by Robert Smyth are Copyright (C) 2008.
//  
//  All Rights Reserved.

#endregion

using System;
using System.Collections.Generic;
using System.IO;
using NUnitGrid.Framework.Logging;
using NUnitGrid.Protocol;
using NUnitGrid.Protocol.Commands;
using ProxyServer.Server;


namespace NUnitGrid.GridClient.Plugins.GridClient.NUnitTestsFinder
{
    public class TestSession : IGridTaskTransactionListener
    {
        private readonly string[] fixtures;
        private readonly IGridServerProxy gridServer;
        private readonly ILogger logger;
        private readonly IRunCompleteListener runCompleteListener;
        private readonly Dictionary<IRunOnGridTask, string> runningTasks = new Dictionary<IRunOnGridTask, string>();
        private readonly IRunSessionListener runSessionListener;
        private readonly Guid sessionID = Guid.NewGuid();
        private readonly TimeSpan taskTimeLimit = TimeSpan.FromMinutes(3);
        private int completedCount;
        private int failedFixturesCount;
        private int passedFixturesCount;

        public TestSession(IGridServerProxy gridServer, IRunSessionListener runSessionListener,
                           IRunCompleteListener runCompleteListener, string[] fixtures, ILogger logger)
        {
            this.gridServer = gridServer;
            this.fixtures = fixtures;
            this.logger = logger;
            this.runSessionListener = runSessionListener;
            this.runCompleteListener = runCompleteListener;
        }

        public void Start()
        {
            logger.Info.Write("Starting test session\n");

            runSessionListener.OnStarted();
            runSessionListener.OnMesssage("Found {0} fixtures:\n", fixtures.Length);

            if (fixtures.Length > 0)
            {
                var workingDirectory = Path.GetDirectoryName(ClientSettings.Default.TestAssembly);
                var testAssembly = Path.GetFileName(ClientSettings.Default.TestAssembly);

                var fixtureCount = 0;
                foreach (var fixture in fixtures)
                {
                    var commandLine =
                        string.Format(
                            @"/run:{0} {1} /domain=none /nologo /nothread /xml=TestResults{2:000}.xml /xmlConsole",
                            fixture, testAssembly, ++fixtureCount);

                    var task = new RunAsProcessTask(Environment.MachineName, "nunit-console.exe", workingDirectory,
                                                    commandLine, taskTimeLimit, "NUnitGridRunner.TargetPath",
                                                    workingDirectory, sessionID);
                    runningTasks.Add(task, fixture);
                    gridServer.RunTask(this, task);
                }
            }
            else
            {
                runSessionListener.OnCompleted(0, 0, true);
            }
        }

        void IGridTaskTransactionListener.OnTaskStarted(object sender)
        {
            logger.Info.Write("Session task started.");
        }

        void IGridTaskTransactionListener.OnTaskCompleted(object sender, bool succeeded, string textOutput,
                                                          string machineName)
        {
            if (!succeeded)
            {
                logger.Info.Write("Session task failed.\n\r{0}", textOutput);
            }
            else
            {
                logger.Info.Write("Session task completed");
            }

            var task = (IRunOnGridTask) sender;
            var fixture = runningTasks[task];
            runningTasks.Remove(task);

            var parser = new NUnitOutputParser(textOutput);

            textOutput = parser.GetSummaryText() + parser.GetFailureText();

            runSessionListener.OnTaskCompleted(fixture, succeeded, machineName, textOutput);

            if (succeeded)
            {
                passedFixturesCount++;
            }
            else
            {
                failedFixturesCount++;
            }

            if (++completedCount == fixtures.Length)
            {
                logger.Info.Write("Session completed.\n");

                runSessionListener.OnCompleted(passedFixturesCount, failedFixturesCount, false);
                runCompleteListener.OnCompleted(passedFixturesCount, failedFixturesCount);
            }
        }
    }
}